﻿using Eplan.EplApi.DataModel;
using System.Collections.Generic;
using System;
using System.Reflection;
using System.Linq;

namespace EplanDevice
{
    public partial class IODevice
    {
        /// <summary>
        /// Параметр времени выполнения устройства.
        /// </summary>
        public class RuntimeParameter : ITag
        {
            /// <summary>
            /// Номер клапана на пневмоострове
            /// </summary>
            public static readonly RuntimeParameter R_VTUG_NUMBER = 
                new(nameof(R_VTUG_NUMBER),
                    "Номер клапана на пневмоострове");

            /// <summary>
            /// Размер области клапана для пневмоострова
            /// </summary>
            public static readonly RuntimeParameter R_VTUG_SIZE = 
                new(nameof(R_VTUG_SIZE),
                    "Размер области клапана для пневмоострова");

            /// <summary>
            /// Номер клапана в AS-i.
            /// </summary>
            public static readonly RuntimeParameter R_AS_NUMBER = 
                new(nameof(R_AS_NUMBER), 
                    "Номер клапана в AS-i");

            /// <summary>
            /// Тип красного сигнала устройства при подаче на него сигнала DO. 
            /// (Постоянный или мигающий). 1 - мигающий, 0 - постоянный.
            /// </summary>
            public static readonly RuntimeParameter R_CONST_RED = 
                new(nameof(R_CONST_RED),
                    "Тип красного сигнала устройства при подаче на него сигнала DO");

            /// <summary>
            /// Номер клеммы пневмоострова для сигнала "Открыть"
            /// </summary>
            public static readonly RuntimeParameter R_ID_ON = 
                new(nameof(R_ID_ON),
                    "Номер клеммы пневмоострова для сигнала 'Открыть'");

            /// <summary>
            /// Номер клеммы пневмоострова для сигнала "Открыть верхнее седло"
            /// </summary>
            public static readonly RuntimeParameter R_ID_UPPER_SEAT = 
                new(nameof(R_ID_UPPER_SEAT),
                    "Номер клеммы пневмоострова для сигнала 'Открыть верхнее седло'");

            /// <summary>
            /// Номер клеммы пневмоострова для сигнала "Открыть нижнее седло"
            /// </summary>
            public static readonly RuntimeParameter R_ID_LOWER_SEAT = 
                new(nameof(R_ID_LOWER_SEAT),
                    "Номер клеммы пневмоострова для сигнала 'Открыть нижнее седло'");

            /// <summary>
            /// Смещение адресного пространства для клапанов 
            /// <see cref="DeviceSubType.V_IOLINK_MIXPROOF"/>, <see cref="DeviceSubType.V_IOLINK_DO1_DI2"/>
            /// привязанных к модулю WAGO.750-657
            /// </summary>
            public static readonly RuntimeParameter R_EXTRA_OFFSET = 
                new(nameof(R_EXTRA_OFFSET),
                    "Смещение адресного пространства для клапана" , true);

            /// <summary>
            /// Номер устройства в <see cref="EY">преобразователе</see>
            /// </summary>
            public static readonly RuntimeParameter R_EY_NUMBER =
                new(nameof(R_EY_NUMBER), "Номер устройства в преобразователе");


            /// <param name="name">Название параметра</param>
            /// <param name="description">Описание параметр</param>
            /// <param name="auto">Метка генерации (параметр заполняется автоматически)</param>
            private RuntimeParameter(
                string name, string description, bool auto = false)
            {
                Name = name;
                Description = description;
                AutoGenerated = auto;
            }


            protected static readonly Lazy<Dictionary<string, RuntimeParameter>> AllParameters = InitParameters();
            private static Lazy<Dictionary<string, RuntimeParameter>> InitParameters()
            {
                return new Lazy<Dictionary<string, RuntimeParameter>>(() =>
                {
                    var parameters = typeof(RuntimeParameter)
                        .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
                        .Where(x => x.FieldType == typeof(RuntimeParameter))
                        .Select(x => x.GetValue(null))
                        .OfType<RuntimeParameter>()
                        .ToDictionary(x => x.Name, x => x);
                    return parameters;
                });
            }


            /// <summary>
            /// Явное преобразование строки в параметр
            /// </summary>
            public static explicit operator RuntimeParameter(string parameterName)
            {
                if (AllParameters.Value.TryGetValue(parameterName, out var parameter))
                {
                    return parameter;
                }
                else
                {
                    return new RuntimeParameter(parameterName, string.Empty);
                }
            }


            /// <summary>
            /// Неявное преобразование параметра в строку
            /// </summary>
            public static implicit operator string(RuntimeParameter parameterType)
            {
                return parameterType.Name;
            }

            public string Name { get; private set; }


            public string Description { get; private set; }

            /// <summary>
            /// Параметр настраивается автоматически
            /// </summary>
            /// <remarks>
            /// Если свойство не установлено то в логах не отображается ошибки
            /// </remarks>
            public bool AutoGenerated { get; private set; }
        }
    }
}
